/**
 * TODO: Copyright info
 */

#ifndef _DATAMATCHER_HPP_
#define _DATAMATCHER_HPP_

#include <cstdint>
#include <functional>
#include <memory>
#include <vector>
#include <string>
#include "Common.hpp"

namespace Navinfo {
namespace Engine {

/**
 * @brief Segment of match result.
 * 
 * Segment is a part of match result. It contains matched link sequence with some descriptions.
 * The order in link sequence vector only means matching order. It doesn't reveal route connectivity.
 * Consider different input and matching process, the segment can start/end with link or point.
 * Use m_IsStartFromLink and m_IsEndToLink to check whether the segment start/end with link.
 * If not, m_StartPoint and m_EndPoint represent the start/end point.
 * 
 * Each segment has a segment order. This can be used to check with previous segment order to decide the type of this segment.
 * - If greater than previous, means this segment is the NEXT of previous segment in the whole match result.
 * - If same with previous, means this segment is just an CANDIDATE to previous segment.
 * Which means, normally, only one candidates should be used, depending on cases.
 */
struct MatchResultSegment
{
    uint32_t   m_SegmentOrder;                       ///< Match order of this segment.
    bool       m_IsStartFromLink;                    ///< Whether start from link.
    bool       m_IsEndToLink;                        ///< Whether end to link.
    uint32_t   m_FirstLinkLength;                    ///< Used length of the first link, calculate forward from start point of travel direction.
    uint32_t   m_LastLinkLength;                     ///< Used length of the last link, calculate backward from end point of travel direction.
    Pos3D      m_StartPoint;                         ///< The start point, if not start from link.
    Pos3D      m_EndPoint;                           ///< The end point, if not end to link.
    std::vector<DirectedLinkID> m_LinkSequence;      ///< All matched links.
};

/**
 * @brief Result of data match.
 * 
 * The result is a combination with several segments.
 */
struct DataMatcherResult
{
    std::vector<MatchResultSegment> m_Segments;      ///< All segments for the result.
};

class DataMatcher
{
protected:
    virtual ~DataMatcher() {};

public:
    /**
     * @brief Match SD route to HD with OpenLR.
     * 
     * @param InputStream     Input stream of OpenLR.
     * @param MatchResult     Match result.
     * @return true           Success
     * @return false          Failed
     */
    virtual bool MatchOpenLR(const std::vector<uint8_t> &InputStream, std::shared_ptr<DataMatcherResult> &MatchResult) = 0;

    /**
     * @brief Match SD route to HD with cross reference.
     * 
     * @param InputStream     Input stream of cross reference.
     * @param MatchResult     Match result.
     * @return true           Success
     * @return false          Failed
     */
    virtual bool MatchCrossReference(const std::vector<uint8_t> &InputStream, std::shared_ptr<DataMatcherResult> &MatchResult) = 0;

    /**
     * @brief Match SD route to HD with custom format. This is TEST PURPOSE ONLY.
     * 
     * @param InputStream     Input stream of custom format.
     * @param MatchResult     Match result.
     * @return true           Success
     * @return false          Failed
     */
    virtual bool MatchCustomFormat(const std::vector<uint8_t> &InputStream, std::shared_ptr<DataMatcherResult> &MatchResult) = 0;
};

} //namespace Engine
} //namespace Navinfo

#endif //_DATAMATCHER_HPP_